package com.zimin.cloud.webflux.handler;

import com.zimin.common.exception.GraceException;
import com.zimin.shared.enums.ResponseStatusEnum;
import com.zimin.shared.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.function.Function;

/**
 * webflux 全局统一返回
 * 1、{@link ResponseBodyResultHandler}类将response的body返回给前端。所以，我们通过重写该类的
 * #handleResult(ServerWebExchange exchange, HandlerResult result)方法将返回结果进行使用{@link Result}包装
 * 2、调用父类方法 # writeBody(Object body,MethodParameter bodyParameter,ServerWebExchange exchange) 方法，将结果返回给前端
 *
 * @author zimin
 * @since 2021/12/24 5:03 下午
 */
@Slf4j
public class GlobalResponseBodyHandler extends ResponseBodyResultHandler {

    private static MethodParameter METHOD_PARAMETER_MONO_COMMON_RESULT;
    private static final Result RESULT_SUCCESS = Result.ok();

    static {
        try {
            // <1> 获取 METHOD_PARAMETER_MONO_COMMON_RESULT。其中 -1 表示 `#methodForParams` 方法的返回值
            METHOD_PARAMETER_MONO_COMMON_RESULT =
                    new MethodParameter(GlobalResponseBodyHandler.class.getDeclaredMethod("methodForParams"), -1);
        } catch (NoSuchMethodException e) {
            log.info("[static][获取 METHOD_PARAMETER_MONO_COMMON_RESULT 时，找不都方法\");");
            GraceException.display(ResponseStatusEnum.FAILED);
        }
    }

    public GlobalResponseBodyHandler(List<HttpMessageWriter<?>> writers, RequestedContentTypeResolver resolver) {
        super(writers, resolver);
    }

    public GlobalResponseBodyHandler(List<HttpMessageWriter<?>> writers, RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry) {
        super(writers, resolver, registry);
    }

    @Override
    @SuppressWarnings("unchecked")
    public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
        Object returnValue = result.getReturnValue();
        Object body;
        // 1.1 处理返回结果为Mono的情况
        if (returnValue instanceof Mono) {
            body = ((Mono<Object>) returnValue)
                    .map((Function<Object, Object>) GlobalResponseBodyHandler::wrapCommonResult)
                    .defaultIfEmpty(RESULT_SUCCESS);
        } else if (returnValue instanceof Flux) {
            body = ((Flux<Object>) returnValue)
                    .collectList()
                    .map((Function<Object, Object>) GlobalResponseBodyHandler::wrapCommonResult)
                    .defaultIfEmpty(RESULT_SUCCESS);
        } else {
            body = wrapCommonResult(returnValue);
            body = Mono.just(body);
        }
        return writeBody(body, METHOD_PARAMETER_MONO_COMMON_RESULT, exchange);
    }

    private static Mono<Result> methodForParams() {
        return null;
    }

    private static Result wrapCommonResult(Object body) {
        //如果已经是Result类型则直接返回
        if (body instanceof Result) {
            return (Result) body;
        }
        //如果不是，刚包装成Result类型
        return Result.ok(body);
    }

}
